/**
 * 
 */
package com.easidea.tim.service.inventory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springside.core.service.EntityService;

import com.easidea.tim.dao.commodity.ProductDao;
import com.easidea.tim.dao.customer.CustomerDao;
import com.easidea.tim.dao.finance.CustomerAccountListingDao;
import com.easidea.tim.dao.finance.FinanceItemDao;
import com.easidea.tim.dao.finance.ShouldPayDao;
import com.easidea.tim.dao.finance.ShouldPaySummaryDao;
import com.easidea.tim.dao.inventory.CheckInOutDao;
import com.easidea.tim.dao.inventory.CheckInOutItemDao;
import com.easidea.tim.dao.inventory.InventoryDao;
import com.easidea.tim.dao.inventory.StorageDao;
import com.easidea.tim.dao.purchase.PurchaseOrderDao;
import com.easidea.tim.dao.purchase.PurchaseReturnDao;
import com.easidea.tim.dao.purchase.PurchaseReturnItemDao;
import com.easidea.tim.dao.saleorder.SaleOrderDao;
import com.easidea.tim.dao.system.orgnization.StaffDAO;
import com.easidea.tim.entity.commodity.Product;
import com.easidea.tim.entity.finance.CustomerAccountListing;
import com.easidea.tim.entity.finance.FinanceItem;
import com.easidea.tim.entity.finance.ShouldPaySummary;
import com.easidea.tim.entity.inventory.CheckInOut;
import com.easidea.tim.entity.inventory.CheckInOutItem;
import com.easidea.tim.entity.inventory.Storage;
import com.easidea.tim.entity.purchase.PurchaseOrder;
import com.easidea.tim.entity.purchase.PurchaseOrderItem;
import com.easidea.tim.entity.purchase.PurchaseReturn;
import com.easidea.tim.entity.saleorder.SaleOrder;
import com.easidea.tim.entity.saleorder.SaleOrderItem;
import com.easidea.tim.util.Page;

/**
 * @author Harrison
 * 
 */
public class CheckInOutService extends EntityService<CheckInOut, CheckInOutDao> {
	private static Logger log = Logger.getLogger(CheckInOutService.class);

	private StorageDao storageDao;
	private CustomerDao customerDao;
	private CheckInOutItemDao checkInOutItemDao;
	private CheckInOutDao checkInOutDao;
	private InventoryDao inventoryDao;
	private SaleOrderDao saleOrderDao;
	private PurchaseOrderDao purchaseOrderDao;
	private ShouldPaySummaryDao shouldPaySummaryDao;
	private ShouldPayDao shouldPayDao;
	private StaffDAO staffDao;
	private ProductDao productDao;
	private CustomerAccountListingDao customerAccountListingDao; // 客户收支相关
	private FinanceItemDao financeItemDao; // 财务科目
	
	private PurchaseReturnDao purchaseReturnDao; // 采购退货单
	private PurchaseReturnItemDao purchaseReturnItemDao; // 采购退货单明细
	
	

	/**
	 * 
	 * 
	 * @param id
	 * @return
	 */
	public CheckInOut getCheckInOutById(Integer id) {
		CheckInOut cio = null;
		if (id != null) {
			cio = get(id.longValue());
		}
		return cio;
	}
	
	public List GetCheckInOutByid(long id) {
		return this.checkInOutDao.getCheckInOutById(id);
	}
	
	public List<CheckInOutItem> getCheckInOutItemByID(long id){
		return this.checkInOutItemDao.getItemsByOrderId(id);
	}

	/**
	 * 出入库操作
	 * 
	 * 
	 * @param cio
	 * @return <p>
	 * 			 <code>-1</code> : 数据不符合要求，如cio对象是空、item对象是空等
	 * 			 <code>-2</code> : 库存数据不存在 
	 * 			 <code>-3</code> : 销售订单不存在
	 * 			 <code>-4</code> : 采购订单不存在
	 * 			 <code>-5</code> : 出入库的单品正在盘点
	 */
	public short checkInOutProduct(CheckInOut cio) {
		short result = 0;
		if (cio != null) {
			removeTempData(cio);
			boolean isInventorying = isInventorying(cio); // 判断当前出入库数据是否在盘点中
			if (isInventorying) {
				log
						.warn("There is inventory processing with current storage, Check-In-Out is not permited !");
				result = -5;
			}
			
			result = (cio.getDirection()
					.equals(CheckInOut.CHECKINOUT_DIRECTION_CHECKIN)) ? checkInProduct(cio)
					: checkOutProduct(cio);
		}else
			result = -1;
		
		if(result < 0){
			String mesg = null;
			switch (result) {
			case -1:
				mesg = "数据错误，请正确填写出入库信息，或联系管理员 ～！";
				break;
			case -2:
				mesg = "库存数据不存在，请查证后重试～！";
				break;
			case -3:
				mesg = "所填写销售订单编号数据不存在，请查证后重试～！";
				break;
			case -4:
				mesg = "所填写采购订单不存在，请查证后重试～！";
				break;
			case -5:
				mesg = "出入库的布品正在盘点，请稍候再试～！";
				break;
			case -6:
				mesg = "剪样库存不足，请查证后重试～！";
				break;
			case -7:
				mesg = "财务登记错误，请联系系统管理员～！";
				break;
			case -8:
				mesg = "采购退货出库错误，当前状态不允许出库～！";
				break;
			}
			
			if(mesg == null) mesg = "系统错误，请联系管理员～！ [ErrorCode:" + result + "]" ;
			throw new RuntimeException(mesg);
		}
		return result;
	}
	
	/**
	 * <p>
	 * 	检查出入库数据内容是否合法：<br>
	 * 	&nbsp;&nbsp; 1. 数据是否有空值
	 *  &nbsp;&nbsp; 2. 选择的类型和填充数据是否有误
	 * </p>
	 * @param cio
	 * @return
	 */
	private short verifyCheckInOutData(CheckInOut cio){
		//TODO 补充完整
		if(cio == null || cio.getItems() == null){
			return -1; // 空值
		}
		short rtn = 0;
		switch (cio.getType()) {
		case 1:
			//采购入库
			if(cio.getPurchaseOrder() == null || StringUtils.isBlank(cio.getPurchaseOrder().getFlowNo())){
				rtn = -6; //采购订单为空，或未填写采购订单编号
				break;
			}
			
			List<CheckInOutItem> itemList = cio.getItems();
			for(CheckInOutItem it: itemList){
				if(it.getStorage() != null && it.getStorage().getSampleFlag()){
					rtn = -7; //采购订单，不允许录入剪样数据
					break;
				}else if (it.getStorage() == null || it.getInputMeterNum() == null) {
					rtn = -1; //空值
					break;
				}
			}
			break;

		case 2:
			// 退货入库
			break;
		case 3:
			//剪样新增入库
			break;
		case 4:
			//剪样销售退回入库
			break;
		case 5:
			//剪样领用退回入库
			break;
		case -1:
			//销售出库
			break;
		case -2:
			//采购退货出库
			break;
		case -3:
			//剪样销售出库
			break;
		case -4:
			//剪样零用出库
			break;
		case -5:
			//产品转化剪样出库
			break;
		}
		return rtn;
	}

	/**
	 * 判断当前出入库数据是否在盘点中...
	 * 
	 * @param cio
	 * @return
	 */
	private boolean isInventorying(CheckInOut cio) {
		if (cio != null && cio.getItems() != null && cio.getItems().size() > 0) {
			boolean isInventorying = inventoryDao.isInventoryThisProductNow(cio
					.getItems().get(0).getStorage().getProduct().getId(), cio.getItems().get(0).getStorage().getSampleFlag());
			return isInventorying;
		}
		return false;
	}

	/**
	 * 入库，对库存数据进行新增，同时进行财务数据的处理
	 * 
	 * @param cio
	 * @return
	 */
	private short checkInProduct(CheckInOut cio) {
		short rtn = 0;
		if (cio != null
				&& cio.getDirection() == CheckInOut.CHECKINOUT_DIRECTION_CHECKIN) {
			// 入库操作
			if (cio.getType().equals(
					CheckInOut.CHECKINOUT_TYPE_CHECKIN_PURCHASE)) {
				//采购入库，需要进行财务数据(应付账款)登记
				log.debug("save the finance data with purchase order ! ");

				if (cio.getPurchaseOrder() != null
						&& cio.getPurchaseOrder().getPurchaseOrderNum() != null) {
					// 财务登记应付款项
					// PurchaseOrder po = purchaseOrderDao.get(cio
					// .getPurchaseOrder().getId());
					PurchaseOrder po = purchaseOrderDao.getPOByPon(cio.getPurchaseOrder().getPurchaseOrderNum());
					if (po != null ) {
						cio.setPurchaseOrder(po);
						
						double totalPurchaseCheckInAmount = summPurchaseCheckInAmount(po.getItems(), cio.getItems());
						log.info(" CheckIn PurchaseAmount: " + totalPurchaseCheckInAmount + " with PON : " + po.getPurchaseOrderNum());
						
						ShouldPaySummary paySum = shouldPaySummaryDao.saveOrUpdateShouldPaySummary(po.getSupplier().getId(), totalPurchaseCheckInAmount);
						// log the shouldPaySum Amount
						shouldPayDao.saveOrUpdateShouldPay(po, paySum, totalPurchaseCheckInAmount); //记账
						log.info("logged purchaseOrder amount: " +paySum.getAmount()+" with PurchaseOrderNum: " + po.getPurchaseOrderNum());
					} else {
						rtn = -4;
						log
								.error("can not save the check in data for total amount is null or purchase order not exists !");
						return rtn;
					}
				}
			}
			checkInOutDao.save(cio);
			for (CheckInOutItem item : cio.getItems()) {
				Storage checkInStorage = item.getStorage();
				if(checkInStorage != null && checkInStorage.getSampleFlag()){
					// 如果是剪样相关的入库，直接进行数据更新
					List<Storage> stoList = storageDao.getSampleStorage(item.getStorage().getProduct().getId());
					if (stoList != null && stoList.size() > 0) {
						Storage existSto = stoList.get(0);
						existSto.setMeterNum(existSto.getMeterNum()
//							+ item.getStorage().getMeterNum()); -- 老代码，有问题，会产生transient object not save 的异常
								+ item.getInputMeterNum());
//						storageDao.merge(existSto); // 同步新的库存到DB中
						storageDao.getHibernateTemplate().update(existSto); // 替换merge方法
						item.setStorage(existSto); //替换库存数据为实际库存
					} else {
						// 库存中不存在对应的剪样，新增之
						checkInStorage.setMeterNum(item.getInputMeterNum());
						storageDao.save(checkInStorage);
					}
				}else{
					//如果不是剪样，直接进行库存数据新增
					storageDao.save(checkInStorage);
				}
				checkInOutItemDao.save(item);
			}
		} else {
			log.error("the check in out object is not check-in direction .");
			rtn = -1;
		}
		return rtn;
	}

	/**
	 * 新的出库登记处理
	 * 
	 * @param cio
	 * @return
	 */
	private short checkOutProduct(CheckInOut cio) {
		short rtn = 0;
		if (cio != null
				&& cio.getDirection().equals(
						CheckInOut.CHECKINOUT_DIRECTION_CHECKOUT)
				&& cio.getItems() != null && cio.getItems().size() > 0) {
			// 基本数据检查

			if (cio.getType().equals(
					CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_SALES)
					|| cio.getType().equals(
							CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PRODUCT_SALES)) {
				if(!setProperSaleOrder(cio)){
					return -1;
					// 判断订单是否已发货
				}
			}

			/*** ------------- 剪样出库 --------------------- **/
			if (cio.getType().equals(
					CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_USES)
					|| cio.getType().equals(
							CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_SALES)) {
				// 剪样相关出库
				boolean isGotStorage = true; // 是否获得合适的库存
				
				for(CheckInOutItem item : cio.getItems()){
					//出入库的剪样
					Storage st = item.getStorage();
					if(st != null && st.getProduct() != null && item.getInputMeterNum() != null){
						List<Storage> stoList = storageDao.getSampleStorage(item.getStorage().getProduct().getId());
						//获得剪样库存数据
						if (stoList != null && stoList.size() > 0) {
							Storage oriSt = stoList.get(0);
							if(oriSt != null){
								oriSt.setMeterNum(oriSt.getMeterNum() - item.getInputMeterNum());
								if(oriSt.getMeterNum() < 0){
									rtn = -6;
									log.error("check out sample storage failure: storage meterNum is not enough ~!");
									return rtn;
								}
//								storageDao.merge(oriSt); //保存
								storageDao.getHibernateTemplate().update(oriSt); // 替换merge方法
								item.setStorage(oriSt); //替换库存，否则会出现transient object unsaved 异常
							}else{
								isGotStorage = false;
								log.error("Sample storage is not exist : product.id = "+st.getProduct().getId());
							}
						}else{
							isGotStorage = false;
							log.error("Sample storage is not exist : product.id = "+st.getProduct().getId());
						}
					}
				}

				if (!isGotStorage) {
					log
							.error("check out storage error while the storage data does not exists !");
					rtn = -2;
					//返回 库存数据不存在的提示
					
				} else {
					// 处理完毕，保存出入库数据
					checkInOutDao.save(cio);
					for (CheckInOutItem item : cio.getItems()) {
						item.setCheckInOut(cio);
						checkInOutItemDao.save(item);
					}
					
					rtn = bookingFinanceWithCheckInOut(cio, rtn); //登记财务数据
				}
			} else {
				/** ------------ 剪样转换产品出库 ---------------- **/
				if(cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_TRANSFORM_PRODUCT)){
					rtn = transform2ProductCheckOutProcess(cio, rtn);
				}else if(cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_TRANSFORM_SAMPLE)){
					/** --------------- 非剪样的相关出库 ------------------ **/
					// 大货转剪样出库 
					rtn = transform2SampleCheckOutProcess(cio, rtn);
				}else{
					// 普通大货出库
					rtn = commonProductCheckOutProcess(cio, rtn);
				}
			}
			
		} else {
			log.error("check out data is not the check-out type!");
			rtn = -1;
			// 数据不符合要求
		}
		return rtn;
	}

	/**
	 * 普通大货出库处理，直接根据storage数据，进行查找，并直接进行清理
	 * @param cio
	 * @param rtn
	 * @return
	 */
	private short commonProductCheckOutProcess(CheckInOut cio, short rtn) {
		
		boolean isPurchaseReturnProcess = cio.getType().shortValue() == CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PURCHASE_RETURN;
		if(!isPurchaseReturnProcess){
			//不是采购退货出库
			short removeCount = removeSentStorage(cio); //获取发货的库存数量
			if (removeCount == cio.getItems().size()) {
				// 全部处理完成
				checkInOutDao.save(cio);
				for (CheckInOutItem item : cio.getItems()) {
					item.setCheckInOut(cio);
					checkInOutItemDao.save(item);
				}
				rtn = bookingFinanceWithCheckInOut(cio, rtn);
			} else {
				//回滚先前的storage merge事务
				rtn = -2;
				log.error("storage check out counts does not match !");
			}
		}else{
			//是采购退货，仅保存出入库数据
			
			short removeCount = removeSentStorageByPurchaseReturn(cio); //获取发货的库存数量
			if (removeCount == cio.getItems().size()) {
				// 全部处理完成
				checkInOutDao.save(cio);
				for (CheckInOutItem item : cio.getItems()) {
					item.setCheckInOut(cio);
					checkInOutItemDao.save(item);
				}
				// rtn = bookingFinanceWithCheckInOut(cio, rtn); @TODO 需要记账 
				// 完成了出库业务
				log.info("successfully for sent storage with checkInOut id : " + cio.getId());
				String prOrderFlowNo =  cio.getItems().get(0).getStorage().getChargedFlowNo();
				
				PurchaseReturn prOrder = purchaseReturnDao.getPurchaseByFlowNo(prOrderFlowNo);
				if(prOrder != null && prOrder.getStatus().shortValue()==2){
					//允许处理
					prOrder.setStatus(Short.valueOf("3"));
					prOrder.setModifyTime(new Date());
					prOrder.setModifier(cio.getCreator());
					prOrder.setResponer(cio.getCreator());
					purchaseReturnDao.getHibernateTemplate().update(prOrder);
					log.info("successfully changed the purchase return order status to acomplished : " + prOrder.getFlowNo() + " and with the checkInOut Id: " + cio.getId());
				}else{
					rtn = -8;
					log.error("purchaes return order's status is not valide for sent storage : " + prOrderFlowNo);
				}
			} else {
				//回滚先前的storage merge事务
				rtn = -2;
				log.error("storage check out counts does not match !");
			}
			
			
//			List<Storage> prStList = storageDao.getStorageByPOFlowNo(cio.getPurchaseOrder().getFlowNo());  //提取指定采购单编号的退货锁库数据
//			if(cio != null && cio.getItems() != null && prStList!= null && prStList.size() > 0){
//				PurchaseOrder po = purchaseOrderDao.getPOByFlowNo(cio.getPurchaseOrder().getFlowNo());
//				if(po == null){
//					rtn = -4;
//					log.error("PurchaseReturn CheckInout Failure: po flow no is not exists");
//				}else{
//					cio.setPurchaseOrder(po);
//					cio.setState("0"); //设定初始状态
//					checkInOutDao.save(cio);
//					for (CheckInOutItem item : cio.getItems()) {
//						for(Storage st : prStList){
//							if(st != null 
//									&& st.getChargedFlowNo().equalsIgnoreCase(cio.getPurchaseOrder().getFlowNo()) 
//									&& st.getProduct().getId().longValue() == item.getStorage().getProduct().getId().longValue()
//									&& st.getMeterNum().doubleValue() == item.getStorage().getMeterNum().doubleValue()){
//								item.setStorage(st);
//								item.setCheckInOut(cio);
//								break;
//							}
//						}
//						checkInOutItemDao.save(item);
//					}
//				}// end of po if null
//				
//			}
		}
		return rtn;
	}
	
	/**
	 * 采购退货的出库处理
	 * @param cioId
	 * @return
	 */
	public boolean purchaseReturnCheckOut(Long cioId){
		boolean t = false;
		CheckInOut cio = checkInOutDao.get(cioId);
		if( cio != null && cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PURCHASE_RETURN) ){
			short removeCount = 0;
			for(CheckInOutItem cioItem: cio.getItems()){
				Storage st = cioItem.getStorage();
				st.setModifier(cio.getCreator());
				st.setModifyTime( new Date());
				storageDao.remove(st);
				removeCount++;
			}
			
			if(removeCount > 0 && removeCount == cio.getItems().size()){
				cio.setState("2"); //采购退货发货完毕
//				checkInOutDao.merge(cio);
				checkInOutDao.getHibernateTemplate().update(cio); // 替换merge方法
				
				//TODO 财务记账，等待客户提供记账规则
				t = true;
			}else{
				log.error("storage check out counts does not match !");
				throw new RuntimeException("采购退货出库数据与实际库存数据有误，请检查后重试～！");
			}
		}
		return t;
	}

	/**
	 * 发货出库，扣减对应库存数据
	 * 
	 * @param cio
	 * @return
	 */
	private short removeSentStorage(CheckInOut cio) {
		List<Storage> queryList = new ArrayList<Storage>(); // 当前查询CIO的库存
		for (CheckInOutItem item : cio.getItems()) {
			queryList.add(item.getStorage());
		}
		
		short removeCount = 0;
		for(Storage cioItemStorage : queryList){
			if(cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PRODUCT_SALES) 
					&& cioItemStorage.getChargedFlowNo() != null 
					&& cioItemStorage.getChargedFlowNo().equals(cio.getSaleOrder().getFlowNo())){
				cioItemStorage.setModifier(cio.getCreator());
				cioItemStorage.setModifyTime( new Date());
				storageDao.remove(cioItemStorage);
				removeCount++;
			}
		}
		return removeCount;
	}
	
	/**
	 * 根据出入库信息进行采购退货的出库处理
	 * @param cio
	 * @return
	 */
	private short removeSentStorageByPurchaseReturn(CheckInOut cio){
		List<Storage> queryList = new ArrayList<Storage>(); // 当前查询CIO的库存
		for (CheckInOutItem item : cio.getItems()) {
			queryList.add(item.getStorage());
		}
		
		short removeCount = 0;
		for(Storage cioItemStorage : queryList){
			if(cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PURCHASE_RETURN)
					&& cioItemStorage.getChargedFlowNo() != null ){
				cioItemStorage.setModifier(cio.getCreator());
				cioItemStorage.setModifyTime( new Date());
				storageDao.remove(cioItemStorage);
				removeCount++;
			}
		}
		return removeCount;
	}

	/**
	 * 大货转剪样出库处理
	 * @param cio
	 * @param rtn
	 * @return
	 */
	private short transform2SampleCheckOutProcess(CheckInOut cio, short rtn) {
		CheckInOut sampleCheckIn = new CheckInOut();
		sampleCheckIn.setCreateTime(new Date());
		sampleCheckIn.setCreator(cio.getCreator());
		sampleCheckIn.setModifier(cio.getModifier());
		sampleCheckIn.setModifyTime(new Date());
		sampleCheckIn.setDirection(CheckInOut.CHECKINOUT_DIRECTION_CHECKIN);
		sampleCheckIn.setType(CheckInOut.CHECKINOUT_TYPE_CHECKIN_SAMPLE);
		sampleCheckIn.setMeterNumSummary(cio.getMeterNumSummary());
		sampleCheckIn.setDescription("库存大货转剪样入库，对应大货出库的数据库记录编号：");
		
		List<CheckInOutItem> checkInItems = new ArrayList<CheckInOutItem>();
		
		List<CheckInOutItem> cioItemList = cio.getItems();
		double samplePiNumSummary = 0d;
		long productId = 0;
		
		for(CheckInOutItem cioItem : cioItemList){
			//提取一个大货库存
			Double meterArray[] = {cioItem.getInputMeterNum()};
			List<Storage> existProductStorageList = storageDao.getStorages(cioItem.getStorage().getProduct(), meterArray, false);
			if(existProductStorageList != null && existProductStorageList.size()>=1){
				Storage existProductStorage = existProductStorageList.get(0);
				cioItem.setStorage(existProductStorage); // 替换库存数据，表明该库存被出库
				
				existProductStorage.setModifier(cio.getCreator());
				existProductStorage.setModifyTime(new Date());
				storageDao.remove(existProductStorage); //出库
				
				CheckInOutItem checkInSampleItem = new CheckInOutItem();
				checkInSampleItem.setCheckInOut(sampleCheckIn);
				checkInSampleItem.setCreateTime(new Date());
				checkInSampleItem.setCreator(cio.getCreator());
				checkInSampleItem.setModifier(cio.getModifier());
				checkInSampleItem.setModifyTime(new Date()); 
				checkInSampleItem.setInputMeterNum(existProductStorage.getMeterNum());//初始化一个剪样的入库明细
				
				// 获得大货对应的剪样库存
				List<Storage> existSampleStorageList = storageDao.getSampleStorage(existProductStorage.getProduct().getId());
				if(existSampleStorageList != null && existSampleStorageList.size()>=1){
					// 对应的剪样库存存在
					Storage existSampleStorage = existSampleStorageList.get(0); //提取第一个剪样库存
					
					existSampleStorage.setMeterNum(existSampleStorage.getMeterNum() + checkInSampleItem.getInputMeterNum());
//					storageDao.merge(existSampleStorage); //增加剪样库存
					storageDao.getHibernateTemplate().update(existSampleStorage); //替换merge方法
					
					checkInSampleItem.setStorage(existSampleStorage); //替换库存数据
				}else{
					// 对应剪样库存不存在
					Storage newSampleStorage = new Storage();
					newSampleStorage.setCreateTime(new Date());
					newSampleStorage.setCreator(cio.getCreator());
					newSampleStorage.setModifier(cio.getModifier());
					newSampleStorage.setModifyTime(new Date());
					newSampleStorage.setProduct(existProductStorage.getProduct());
					newSampleStorage.setMeterNum(checkInSampleItem.getInputMeterNum());
					newSampleStorage.setSampleFlag(true);
					newSampleStorage.setName(existProductStorage.getProduct().getName());
					storageDao.save(newSampleStorage); // 新增一个剪样库存
					
					checkInSampleItem.setStorage(newSampleStorage); // 替换成新增库存
				}
				checkInItems.add(checkInSampleItem); //添加到入库的剪样明细数据中
				
				if(productId != 0 && productId == existProductStorage.getProduct().getId().longValue()){
					samplePiNumSummary ++; //增加剪样的匹数
				}else if(productId == 0) {
						samplePiNumSummary = 1;
						productId = existProductStorage.getProduct().getId().longValue();
				}
			}else{
				rtn = -2;
				log.error("commodity product transform to sample storage failure : Caused by product storage is not exists ~!");
//				try {
//					storageDao.getSessionFactory().getCurrentSession()
//							.getTransaction().rollback(); //回滚先前插入的数据
//				} catch (Exception e) {
//					// do nothing
//				}
				return rtn;
			}
		}// end for cioItem loop
		
		checkInOutDao.save(cio);
		for(CheckInOutItem coItem: cio.getItems()){
			checkInOutItemDao.save(coItem);
		}//保存大货出库数据

		sampleCheckIn.setPiNumSummary(samplePiNumSummary);
		sampleCheckIn.setItems(checkInItems);
		sampleCheckIn.setDescription(sampleCheckIn.getDescription() + cio.getId());
		checkInOutDao.save(sampleCheckIn); //保存出入库总记录
		for(CheckInOutItem sampleCheckInItem: sampleCheckIn.getItems()){
			checkInOutItemDao.save(sampleCheckInItem);
		}//保存剪样入库数据
		return rtn;
	}

	/**
	 * 剪样转大货出库处理
	 * @param cio
	 * @param rtn
	 * @return
	 */
	private short transform2ProductCheckOutProcess(CheckInOut cio, short rtn){
		CheckInOut productCheckIn = new CheckInOut();
		productCheckIn.setCreateTime(new Date());
		productCheckIn.setCreator(cio.getCreator());
		productCheckIn.setModifier(cio.getCreator());
		productCheckIn.setDirection(CheckInOut.CHECKINOUT_DIRECTION_CHECKIN);
		productCheckIn.setType(CheckInOut.CHECKINOUT_TYPE_CHECKIN_TRANSFORM_PRODUCT);
		productCheckIn.setDescription("库存剪样转化大货入库，对应剪样出库的数据库记录编号：");
		productCheckIn.setMeterNumSummary(cio.getMeterNumSummary());
		
		List<CheckInOutItem> checkInItems = new ArrayList<CheckInOutItem>();
		
		List<CheckInOutItem> cioItemList = cio.getItems();
		
		double meterNumSummary = 0d;
		for(CheckInOutItem cioItem:cioItemList){
			//循环输入数据的库存
			Storage inputSampleSt = cioItem.getStorage();
			if(inputSampleSt != null && inputSampleSt.getProduct() != null && inputSampleSt.getProduct().getId() != null){
				List<Storage> existSampleStorageList = storageDao.getSampleStorage(inputSampleSt.getProduct().getId());
				if(existSampleStorageList != null && existSampleStorageList.size()>=1){
					// 对应的剪样库存存在
					Storage existSampleStorage = existSampleStorageList.get(0); //提取第一个剪样库存
					
					existSampleStorage.setMeterNum(existSampleStorage.getMeterNum() - cioItem.getInputMeterNum());
					if(existSampleStorage.getMeterNum() < 0){
						rtn = -6;
						log.error("check out sample storage failure : storage meterNum is not enough!");
						return rtn;
					}
					
//					storageDao.merge(existSampleStorage); //扣减剪样库存
					storageDao.getHibernateTemplate().update(existSampleStorage); //替换merge方法
					
					cioItem.setStorage(existSampleStorage); //替换库存数据
					// ------------- 完成剪样的出库时库存的处理 -------------------- //
					
					Storage newProductStorage = new Storage();
					newProductStorage.setCreateTime(new Date());
					newProductStorage.setCreator(cio.getCreator());
					newProductStorage.setModifier(cio.getCreator());
					newProductStorage.setModifyTime(new Date());
					newProductStorage.setMeterNum(cioItem.getInputMeterNum());
					newProductStorage.setName(cioItem.getStorage().getProduct().getName());
					newProductStorage.setProduct(cioItem.getStorage().getProduct());
					newProductStorage.setSampleFlag(false);
					storageDao.save(newProductStorage);
					// 新增产品库存
					
					CheckInOutItem productCheckInItem = new CheckInOutItem();
					productCheckInItem.setCheckInOut(productCheckIn);
					productCheckInItem.setCreateTime(new Date());
					productCheckInItem.setCreator(cio.getCreator());
					productCheckInItem.setModifier(cio.getCreator());
					productCheckInItem.setModifyTime(new Date());
					productCheckInItem.setInputMeterNum(cioItem.getInputMeterNum());
					productCheckInItem.setStorage(newProductStorage);
					checkInItems.add(productCheckInItem);
					
					meterNumSummary = meterNumSummary + cioItem.getInputMeterNum();
					// 新增产品入库明细处理
				}else{
					rtn = -2;
					log.error("check out sample storage with transform2Product failure: storage does not exist ~!");
				}// end for existSampleStorageList
			}
		
		}// end sample storage for loop
		
		checkInOutDao.save(cio);
		for(CheckInOutItem coItem: cio.getItems()){
			checkInOutItemDao.save(coItem);
		}//保存剪样出库数据
		
		productCheckIn.setPiNumSummary((double)checkInItems.size());
		productCheckIn.setMeterNumSummary(meterNumSummary);
		productCheckIn.setDescription(productCheckIn.getDescription() + cio.getId());
		checkInOutDao.save(productCheckIn);
		productCheckIn.setItems(checkInItems);
		for(CheckInOutItem ciItem: productCheckIn.getItems()){
			checkInOutItemDao.save(ciItem);
		}//保存产品入库数据
		
		return rtn;
	}
	
	private short bookingFinanceWithCheckInOut(CheckInOut cio, short rtn ) {
		
		// 进行财务数据处理及销售订单数据处理
		if (cio.getType().equals(
				CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_SALES)
				|| cio.getType().equals(
						CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PRODUCT_SALES)) {
			if (cio.getSaleOrder() != null
					&& cio.getSaleOrder().getFlowNo() != null) {
				SaleOrder so = cio.getSaleOrder();
				if (so != null
						&& so.getStatus().shortValue() == Short
						.parseShort(SaleOrder.order_staus_send)
						&& rtn == 0 ) {
					// 等待发货中
					// 计算出库金额及对账备注
					Map<String, Object> memoAndAmountMap = genCAListingMemo(cio,so); //修改记账方法，原记账方法有错误
					FinanceItem fi = financeItemDao.getSalesAccountItem();
					boolean bookingResult = customerAccountListingDao.bookingFinanceData(so.getCustomer().getId(),
							financeItemDao.getSalesAccountItem().getId(), memoAndAmountMap, cio.getCreator());
					
					if(bookingResult){
						log.warn(" start change saleorder status : " + so.getId() + " , original status : " + so.getStatus());
						so.setStatus(Short.valueOf(SaleOrder.order_staus_over));
						so.setModifyTime(new Date()); //打印码单需求
						so.setModifier(cio.getCreator()); // 打印码单需求
//						saleOrderDao.merge(so);//
						saleOrderDao.getHibernateTemplate().update(so);// 替换merge方法
						log.warn(" end saleorder " + so.getId() + " status changed (new value: " + so.getStatus() +  "), saleorder has been sent ~~!");
					}else{
						log.error(" ERROR before saleorder status changed ~~! caused by booking finance error ~!");
						rtn = -7;
						return rtn;
					}
					
				} else {
					log
					.error("checkout data save error caused by saleorder is null or status not match !");
					rtn = -3;
					return rtn;
				}
			} else {
				log
				.error("checkout data save error , caused by parameter error !");
				rtn = -3;
				return rtn;
			}
		}
		return rtn;
	}
	
	/**
	 * 进行财务数据的备注信息生成
	 * @param cio
	 * @param so
	 * @return
	 */
	private Map<String, Object> genCAListingMemo(CheckInOut cio , SaleOrder so){
		List<SaleOrderItem> soItemList = so.getItems();
		StringBuffer memoSB = new StringBuffer(so.getFlowNo()+"；\n");
		DecimalFormat df = new DecimalFormat("0.##");
		
		if(cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PRODUCT_SALES) || cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_SALES)){
			//产品销售或剪样销售
			for(SaleOrderItem soItem : soItemList){
				memoSB.append("[销]");
				double currentMeterNumSum = 0d;
				String soMeterStrArray[] = soItem.getMeterNum().split(",");
				for(int i=0;i<soMeterStrArray.length;i++){
					currentMeterNumSum = currentMeterNumSum + Double.valueOf(soMeterStrArray[i]).doubleValue();
				}
				memoSB.append(soItem.getProduct().getName() + "["+df.format(currentMeterNumSum) +"米×"+ soItem.getMoneyNum()+"元/米]\n");
			}
		}
		
		Map<String, Object> rtnMap = new HashMap<String, Object>();
		rtnMap.put("memo", memoSB.toString());
		rtnMap.put("amountsummary", so.getMoneyNum());
		log.info("Customer Account Listing memo : " + memoSB.toString());
		return rtnMap;
	}
	
	/**
	 * 获取销售退回的财务备注信息
	 * @param cio
	 * @param so
	 * @return
	 */
	private Map<String, Object> genSalesReturnCAListingMemo(CheckInOut cio , SaleOrder so){
		List<SaleOrderItem> soItemList = so.getItems();
		StringBuffer memoSB = new StringBuffer("销售退回："+so.getFlowNo()+"；\n");
		DecimalFormat df = new DecimalFormat("0.##");
		
		if(cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKIN_SAMPLE_SALES_RETURN) || cio.getType().equals(CheckInOut.CHECKINOUT_TYPE_CHECKIN_RETURN)){
			//产品或剪样的销售退回
			for(SaleOrderItem soItem : soItemList){
				double currentMeterNumSum = 0d;
				String soMeterStrArray[] = soItem.getMeterNum().split(",");
				for(int i=0;i<soMeterStrArray.length;i++){
					currentMeterNumSum = currentMeterNumSum + Math.abs(Double.valueOf(soMeterStrArray[i]).doubleValue());
				}
				memoSB.append("[销退]" + soItem.getProduct().getName() + "["+df.format(currentMeterNumSum) +"米×"+ soItem.getMoneyNum()+"元/米]\n");
			}
		}
		
		Map<String, Object> rtnMap = new HashMap<String, Object>();
		rtnMap.put("memo", memoSB.toString());
		rtnMap.put("amountsummary", Math.abs(so.getMoneyNum()));
		log.info("Customer Account Listing memo : " + memoSB.toString());
		return rtnMap;
	}

	/**
	 * 根据采购合同和入库清单计算入库金额
	 * @param po
	 * @param cioItems
	 * @return
	 */
	private double summPurchaseCheckInAmount(List<PurchaseOrderItem> poItemList, List<CheckInOutItem> cioItems){
		double totalAmount = 0.0d;
		Map<Long, Double> poItemPriceMap = new HashMap<Long, Double>();
		Map<Long, Double> cioItemMeterSumMap = new HashMap<Long, Double>();
		
		if(poItemList != null && poItemList.size()>0 && cioItems != null && cioItems.size() > 0){
			for(PurchaseOrderItem poItem : poItemList){
				if(poItem != null && !poItemPriceMap.containsKey(poItem.getProductId())){
					//不包含
					poItemPriceMap.put(poItem.getProductId(),poItem.getProductPurchasePrice());
				}
			}// end of initialized poItemPriceMap
			
			
			for(CheckInOutItem cioItem: cioItems){
				if(cioItem != null && cioItem.getStorage() != null 
						&& cioItem.getStorage().getProduct() != null 
						&& cioItem.getStorage().getProduct().getId() != null
						&& cioItem.getInputMeterNum() != null){
					
					if(cioItemMeterSumMap.containsKey(cioItem.getStorage().getProduct().getId())){
						//存在对应米数
						Double tmpMeter = (Double)cioItemMeterSumMap.get(cioItem.getStorage().getProduct().getId());
						tmpMeter = tmpMeter + cioItem.getInputMeterNum();
						cioItemMeterSumMap.put(cioItem.getStorage().getProduct().getId(), tmpMeter);
					}else{
						cioItemMeterSumMap.put(cioItem.getStorage().getProduct().getId(), cioItem.getInputMeterNum());
					}
				}
			} // end of initialized cioItemMeterSumMap
			
			if(!cioItemMeterSumMap.isEmpty() && !poItemPriceMap.isEmpty()){
				Iterator<Long> productIdKeys = cioItemMeterSumMap.keySet().iterator();
				while (productIdKeys.hasNext()) {
					Long productIdKey = (Long) productIdKeys.next();
					Double productMeterSum = cioItemMeterSumMap.get(productIdKey);
					if(poItemPriceMap.containsKey(productIdKey)){
						Double productPrice = (Double)poItemPriceMap.get(productIdKey);
						if(productPrice != null){
							totalAmount = totalAmount + productPrice * productMeterSum;
						}
					}
					
				}// end of calculate sum amount
			}
		}
		
		return totalAmount;
	}

	/**
	 * 
	 * @param checkInOutStorageSampleFlag
	 * @param saleOrderTypeString
	 * @return
	 */
	private boolean isSampleFlagEquals(boolean checkInOutStorageSampleFlag,
			String saleOrderTypeString) {
		boolean t = false;
		if (checkInOutStorageSampleFlag) {
			if (saleOrderTypeString.equals(SaleOrder.order_type_sample)) {
				// 剪样销售
				t = true;
			}
		} else {
			if (saleOrderTypeString.equals(SaleOrder.order_type_sale)) {
				// 正常销售
				t = true;
			}
		}
		return t;
	}

	/**
	 * 
	 * @param cio
	 */
	private boolean setProperSaleOrder(CheckInOut cio) {
		if (cio.getType().equals(
				CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_SALES)
				|| cio.getType().equals(
						CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PRODUCT_SALES)) {
			
			if (cio.getSaleOrder() != null
					&& cio.getSaleOrder().getFlowNo() != null
					&& cio.getSaleOrder().getFlowNo().trim().length() > 0
					&& cio.getSaleOrder().getMeterNum() == null) {
				short status = cio.getSaleOrder().getStatus();
				if(status == new Integer(4).shortValue()){
					return false;
				}

				SaleOrder so = saleOrderDao.getSaleOrderByFlowNo(cio
						.getSaleOrder().getFlowNo());

				if (so != null && so.getId() != null) {
					cio.setSaleOrder(so);
				}
			}
		}
		return true;
	}

	/**
	 * 临时数据清理
	 */
	private void removeTempData(CheckInOut cio) {
		if (cio != null) {
			if (cio.getId() != null && cio.getId() == -1)
				cio.setId(null);
			if (cio.getCreateTime() == null)
				cio.setCreateTime(new Date());
			if (cio.getModifyTime() == null)
				cio.setModifyTime(new Date());
			if (cio.getModifier() == null && cio.getCreator() != null)
				cio.setModifier(cio.getCreator());
			if (cio.getItems() != null && cio.getItems().size() > 0) {
				for (CheckInOutItem item : cio.getItems()) {
					if (item.getId() != null && item.getId() == -1)
						item.setId(null);
					if (item.getCreator() == null && cio.getCreator() != null)
						item.setCreator(cio.getCreator());
					if (item.getCreateTime() == null)
						item.setCreateTime(new Date());
					if (item.getModifier() == null && cio.getCreator() != null)
						item.setModifier(item.getCreator());
					if (item.getModifyTime() == null)
						item.setModifyTime(new Date());

					Storage stg = item.getStorage();
					if (stg.getId() != null && stg.getId() == -1)
						stg.setId(null);
					if (stg.getCreator() == null && cio.getCreator() != null)
						stg.setCreator(cio.getCreator());
					if (stg.getCreateTime() == null)
						stg.setCreateTime(new Date());
					if (stg.getModifier() == null && cio.getCreator() != null)
						stg.setModifier(cio.getCreator());
					if (stg.getModifyTime() == null)
						stg.setModifyTime(new Date());

					if (cio.getType().shortValue() == CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PRODUCT_SALES
							&& cio.getSaleOrder().getFlowNo() != null) {
						stg.setChargeFlag(true);
						stg.setChargedFlowNo(cio.getSaleOrder().getFlowNo());
					}
				}
			}
		}
	}

	/**
	 * 查询相应记录
	 * 
	 * @param operator
	 * @param billFlowNum
	 * @param billType
	 * @param searchStartDate
	 * @param searchEndDate
	 * @param productName
	 * @param colorCode
	 * @return
	 */
	public Page queryCheckInOutList(Integer cioType, String operator,
			String billFlowNum, Integer billType, Date searchStartDate,
			Date searchEndDate,String state, String productName, String colorCode, Page page) {

//		Criteria cte = genListCriteria(cioType, operator, billFlowNum,
//				billType, searchStartDate, searchEndDate);
//		cte.setProjection(Projections.count("id"));
//		Integer totalCounts = (Integer) cte.uniqueResult();
//
//		cte = genListCriteria(cioType, operator, billFlowNum, billType,
//				searchStartDate, searchEndDate);
//		cte.addOrder(Order.desc("createTime"));
//		
//		cte.setFirstResult(index);
//		cte.setMaxResults(page.getPageSize());
		
		
		Integer counts = getCIOQueryListCounts(cioType, operator,
				billFlowNum, billType, searchStartDate,searchEndDate,state, productName, colorCode);
		
		int index = Page.getStartOfPage(page.getCurrentPageNo(), page
				.getPageSize());
		
		List<Object[]> rtl = (List<Object[]>) getCIOQueryListPageList(cioType, operator,
				billFlowNum, billType, searchStartDate,searchEndDate,state, productName, colorCode, 
				index, page.getPageSize());

		if(rtl != null && rtl.size() > 0){
			for(short i=0;i<rtl.size();i++){
				Object[] data = rtl.get(i);
				if(data != null && data.length > 0){
					data[8] = ((BigDecimal)data[8]).doubleValue();
				}
			}
		}//数据转换，调整米数
		
		Page resultPage = new Page(index, counts, page.getPageSize(), rtl);
		resultPage.setCurrentPageNo(page.getCurrentPageNo());

		return resultPage;
	}
	
	/**
	 * 获得CIO Query List的counts
	 * @param cioType
	 * @param operator
	 * @param billFlowNum
	 * @param billType
	 * @param searchStartDate
	 * @param searchEndDate
	 * @param productName
	 * @param colorCode
	 * @return
	 */
	private Integer getCIOQueryListCounts(Integer cioType, String operator,
			String billFlowNum, Integer billType, Date searchStartDate,
			Date searchEndDate,String state, String productName, String colorCode){
		final String sql = genCIOQueryListSQL(cioType,operator,billFlowNum,billType,searchStartDate, searchEndDate,state, true, productName, colorCode);
		return (Integer)checkInOutDao.getHibernateTemplate().execute(new HibernateCallback(){
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				List<Object> rst = query.list();
				if(rst != null && rst.size() >= 1){
					return ((BigInteger)rst.get(0)).intValue();
				}else
					return 0;
			}
		});
	}
	
	private List<Object[]> getCIOQueryListPageList(Integer cioType, String operator,
			String billFlowNum, Integer billType, Date searchStartDate,
			Date searchEndDate,String state, String productName, String colorCode, 
			Integer startIndex, Integer pageSize){
		
		StringBuffer sqlBuf = new StringBuffer(genCIOQueryListSQL(cioType,operator,billFlowNum,billType,searchStartDate, searchEndDate,state, false, productName, colorCode));
		if(startIndex != null && pageSize != null){
			sqlBuf.append(" LIMIT " + startIndex + ", " + pageSize);
		}
		final String sql = sqlBuf.toString();
		
		return (List<Object[]>)checkInOutDao.getHibernateTemplate().execute(new HibernateCallback(){
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				return (List<Object[]>) query.list();
			}
		});
	}
	
	/**
	 * 生成出入库数据查询记录SQL 
	 * @param cioType
	 * @param operator
	 * @param billFlowNum
	 * @param billType
	 * @param searchStartDate
	 * @param searchEndDate
	 * @param isCount
	 * @param productName
	 * @param colorCode
	 * @return
	 */
	private String genCIOQueryListSQL (Integer cioType,String operator,String billFlowNum,
			Integer billType, Date searchStartDate, Date searchEndDate,String state, boolean isCount, String productName, String colorCode){
		StringBuffer sb = new StringBuffer(
				" FROM tim_inventory_checkinout_item it , tim_inventory_checkinout cio , tim_inventory_storage st, tim_commodity_product p " +
				" WHERE cio.id = it.checkinout_id AND it.storage_id = st.id AND st.product_id = p.id AND cio.deleted = 0");

		if(billType != null && StringUtils.isNotBlank(billFlowNum)){
			int whereClausIndex = sb.indexOf("WHERE");
			if(billType.intValue() == 1){
				sb.insert(whereClausIndex, " , tim_purchase_order po ");
				sb.append(" AND po.id = cio.purchase_order_id AND po.flowNo'" + billFlowNum + "'");
			}else if (billType.intValue() == -1 || billType.intValue() == -3) {
				sb.insert(whereClausIndex, ", tim_salesoder_order so ");
				sb.append(" AND so.id = cio.sale_order_id  AND so.flowNo = '" + billFlowNum + "'");
			}
		}
		
		if(cioType != null){
			sb.append(" AND cio.type = " + cioType);
		}
		
		if(StringUtils.isNotBlank(operator)){
			sb.append(" AND cio.creator = '" + operator + "'");
		}
		
		if(StringUtils.isNotBlank(state)){
			sb.append(" AND cio.state = '" + state + "'");
		}
		if(searchStartDate != null && searchEndDate != null){
			SimpleDateFormat  sdf = new SimpleDateFormat ("yyyy-MM-dd 00:00:00");
			sb.append(" AND cio.create_time >= '" + sdf.format(searchStartDate) + "' and cio.create_time <= '" + sdf.format(searchEndDate) + "'");
		}
		
		/* -- added for productName and colorCode --*/
		if(StringUtils.isNotEmpty(productName)){
			sb.append(" AND p.name = '" + productName.trim() + "'");
		}
		
		if(StringUtils.isNotEmpty(colorCode)){
			sb.append(" AND p.color_code = '" + colorCode.trim() + "'");
		}

		if(isCount){
			sb.insert(0, "SELECT COUNT(distinct p.id) ");
		}else{
			sb.insert(0, "SELECT cio.id,cio.state, p.id, p.name, p.color_code, st.sample_flag, DATE_FORMAT(cio.create_time,'%Y-%m-%d') AS createTime,COUNT(it.id) AS piNum, SUM(it.input_meter_num) AS meterNum , cio.creator ");
			sb.append(" GROUP BY p.id, createTime ORDER BY cio.create_time DESC ");
		}
		log.debug("cio query list sql : " + sb.toString());
		return sb.toString();
	}

	/**
	 * @param operator
	 * @param billFlowNum
	 * @param billType
	 * @param searchStartDate
	 * @param searchEndDate
	 * 
	 * @deprecated
	 */
	private Criteria genListCriteria(Integer cioType, String operator,
			String billFlowNum, Integer billType, Date searchStartDate,
			Date searchEndDate) {
		Criteria cte = checkInOutDao.createUnDeletedCriteria();
		if (operator != null && operator.trim().length() > 0) {
			cte.add(Restrictions.eq("creator", operator));
		}
		if (billType != null) {
			switch (billType) {
			case 1:
				// 采购入库 ，需判断billFlowNo
				if (billFlowNum != null && billFlowNum.trim().length() > 0) {
					cte.createAlias("purchaseOrder", "purchaseOrder");
					cte.add(Restrictions.eq("purchaseOrder.purchaseOrderNum",
							billFlowNum));
				}
				break;

			case -1:
				// 产品销售出库
				if (billFlowNum != null && billFlowNum.trim().length() > 0) {
					cte.createAlias("saleOrder", "saleOrder");
					cte.add(Restrictions.eq("saleOrder.saleOrderNum",
							billFlowNum));
				}
				break;
			case -3:
				// 剪样销售出库
				if (billFlowNum != null && billFlowNum.trim().length() > 0) {
					cte.createAlias("saleOrder", "saleOrder");
					cte.add(Restrictions.eq("saleOrder.saleOrderNum",
							billFlowNum));
				}
				break;
			}
		}
		if (searchStartDate != null && searchEndDate != null
				&& searchStartDate.before(searchEndDate))
			cte.add(Restrictions.between("createTime", searchStartDate,
					searchEndDate));
		if (cioType != null) {
			cte.add(Restrictions.eq("type", cioType.shortValue()));
		}
		return cte;
	}

	/**
	 * 根据销售订单/采购退货单进行出库操作
	 * 
	 * @param saleOrderId
	 * @param creator
	 * @param isSample
	 * @return
	 */
	public boolean checkOutBySaleOrder(Long saleOrderId, String creator) {
		boolean t = false;
		if (saleOrderId != null && creator != null) {
			SaleOrder so = saleOrderDao.get(saleOrderId); //先获取对应的订单数据
			if (so != null && so.getFlowNo() != null) {
				CheckInOut cio = new CheckInOut();
				cio.setDirection(CheckInOut.CHECKINOUT_DIRECTION_CHECKOUT);
				if (so.getOrderType().equals(SaleOrder.order_type_sale)) {
					cio
							.setType(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PRODUCT_SALES);
				}
				if (so.getOrderType().equals(SaleOrder.order_type_sample)) {
					cio
							.setType(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_SALES);
				}

				cio.setCreator(creator);
				cio.setCreateTime(new Date());
				cio.setModifier(creator);
				cio.setModifyTime(new Date());
				cio.setSaleOrder(so);

				if(cio.getType().shortValue() == CheckInOut.CHECKINOUT_TYPE_CHECKOUT_SAMPLE_SALES){
					injectSampleCheckinoutItem(so,cio,creator);
				}else{
					injectCheckinoutItems(cio, so.getFlowNo(),creator);
				}
				
				short result = checkInOutProduct(cio); // 数据保存
				if (result >= 0)
					t = true;
			}
		}
		return t;
	}

	/**
	 * 采购退货发货
	 * @param prOrderId
	 * @param creator
	 * @return
	 */
	public boolean checkOutByPurchaseReturn(Long prOrderId, String creator){
		boolean t = false;
		if(prOrderId != null && StringUtils.isNotBlank(creator)){
			// 采购退货
			PurchaseReturn prOrder = purchaseReturnDao.get(prOrderId);
			if(prOrder != null && StringUtils.isNotBlank(prOrder.getFlowNo())){
				CheckInOut cio = new CheckInOut();
				cio.setDirection(CheckInOut.CHECKINOUT_DIRECTION_CHECKOUT);
				cio.setType(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PURCHASE_RETURN);
				cio.setCreator(creator);
				cio.setCreateTime(new Date());
				cio.setModifier(creator);
				cio.setModifyTime(new Date());
				cio.setDescription("系统协助采购退货出库，出库单号：" + prOrder.getFlowNo());
				injectCheckinoutItems(cio, prOrder.getFlowNo(),creator); //填充明细数据
				short result = checkInOutProduct(cio); // 数据保存
				if (result >= 0)
					t = true;
			}
		}else{
			log.error("can not execute purchase return storages sent , caused by orderId or creator is null ~! ");
		}
		return t;
	}
	
	/**
	 * 根据销售退货信息进行退货入库
	 * 操作时，先进行入库处理，随后进行财务数据登记，记账“退货结算”科目
	 * 
	 * @param saleOrderId
	 * @param creator
	 * @return
	 */
	public boolean checkInBySalesReturn (Long saleOrderId, String creator){
		boolean t = false;
		
		if(saleOrderId != null && StringUtils.isNotBlank(creator)){
			SaleOrder so = saleOrderDao.get(saleOrderId);
			if(so == null){
				log.error("SaleOrder does not exist with Id: " + saleOrderId+", process checkInBySalesReturn failure ~! ");
				return t;
			}
			
			CheckInOut checkIn = new CheckInOut();
			checkIn.setCreateTime(new Date());
			checkIn.setCreator(creator);
			checkIn.setModifier(creator);
			checkIn.setModifyTime(new Date());
			checkIn.setDescription("系统自动销售退货入库 ：" + so.getFlowNo());
			checkIn.setDirection(CheckInOut.CHECKINOUT_DIRECTION_CHECKIN);
			checkIn.setSaleOrder(so);

			List<CheckInOutItem> ciItemList = new ArrayList<CheckInOutItem>();
			
			List<SaleOrderItem> soItemList = so.getItems();
			
			Storage sampleStorage = null;
			if(so.getOrderType().equalsIgnoreCase(SaleOrder.order_type_sample_return)){
				// 剪样退货
				checkIn.setType(CheckInOut.CHECKINOUT_TYPE_CHECKIN_SAMPLE_SALES_RETURN);
				
				checkIn.setPiNumSummary((double)soItemList.size());
				double totalSampleMeterNum = 0d;
				
				for(SaleOrderItem soItem : soItemList){
					String[] meterArray = soItem.getMeterNum().split(",");
					double meterNum = Math.abs(Double.valueOf(meterArray[0]));
					totalSampleMeterNum = totalSampleMeterNum + meterNum;

					CheckInOutItem sampleCIItem = new CheckInOutItem();
					sampleCIItem.setCheckInOut(checkIn);
					sampleCIItem.setCreateTime(new Date());
					sampleCIItem.setCreator(creator);
					sampleCIItem.setModifier(creator);
					sampleCIItem.setModifyTime(new Date());
					sampleCIItem.setInputMeterNum(meterNum);
					
					Storage newSampleStorage = new Storage();
					newSampleStorage.setCreateTime(new Date());
					newSampleStorage.setCreator(creator);
					newSampleStorage.setModifier(creator);
					newSampleStorage.setModifyTime(new Date());
					newSampleStorage.setName(soItem.getProductName());
					newSampleStorage.setProduct(soItem.getProduct());
					newSampleStorage.setSampleFlag(true);
					sampleCIItem.setStorage(newSampleStorage);
					ciItemList.add(sampleCIItem);
				}
				checkIn.setMeterNumSummary(totalSampleMeterNum);
			}else if(so.getOrderType().equalsIgnoreCase(SaleOrder.order_type_salereturn)){
				// 销售退货
				checkIn.setType(CheckInOut.CHECKINOUT_TYPE_CHECKIN_RETURN);

				double totalPiNum = 0d;
				double totalMeter = 0d;
				for(SaleOrderItem soItem : soItemList){
					String[] meterArray = soItem.getMeterNum().split(",");
					
					for(String meterStr : meterArray){
						double meterNum = Math.abs(Double.valueOf(meterStr));
						totalMeter = totalMeter + meterNum;
						totalPiNum ++;

						CheckInOutItem productCIItem = new CheckInOutItem();
						productCIItem.setCheckInOut(checkIn);
						productCIItem.setCreateTime(new Date());
						productCIItem.setCreator(creator);
						productCIItem.setModifier(creator);
						productCIItem.setModifyTime(new Date());
						productCIItem.setInputMeterNum(meterNum);
						
						totalMeter = totalMeter + meterNum;
						
						Storage newPdtSt = new Storage();
						newPdtSt.setCreateTime(new Date());
						newPdtSt.setCreator(creator);
						newPdtSt.setModifier(creator);
						newPdtSt.setModifyTime(new Date());
						newPdtSt.setName(soItem.getProductName());
						newPdtSt.setProduct(soItem.getProduct());
						newPdtSt.setSampleFlag(false);
						newPdtSt.setMeterNum(meterNum);
						
						productCIItem.setStorage(newPdtSt);
						
						ciItemList.add(productCIItem);
					}
				}
				checkIn.setPiNumSummary(totalPiNum);
				checkIn.setMeterNumSummary(totalMeter);
				
			}else{
				log.error("SaleOrder type is not the sale_returen or sample_return ~! ");
				return t;
			} // end of the if isSample
			
			checkIn.setItems(ciItemList);
			
			short result = checkInOutProduct(checkIn); // 数据保存
			if (result >= 0){
				// 入库成功，准备进行财务数据登记
				
				CustomerAccountListing cal = new CustomerAccountListing();
				cal.setCustomer(so.getCustomer());
				cal.setCustomerName(so.getCustomer().getName());
				FinanceItem fi = financeItemDao.getSalesReturnAccountItem(); // 退货结算科目
				cal.setItem(fi);
				cal.setItemName(fi.getName());
				
				// 计算出库金额及对账备注
//				Map<String, Object> memoAndAmountMap = genCheckOutAmountAndAccountListingMemo(
//						cio, so);
				Map<String, Object> memoAndAmountMap = genSalesReturnCAListingMemo(checkIn,so); //获得销售退回的记账备注信息
				String memo = (String) memoAndAmountMap.get("memo");
				Double amountSummary = (Double) memoAndAmountMap.get("amountsummary");
				cal.setMemo(memo);
				cal.setAmount(amountSummary);
				cal.setCreator(creator);
				cal.setModifier(creator);
				
				boolean bookAccountSuccess = customerAccountListingDao.addCustomerAccoutListing(cal);
				if(bookAccountSuccess){
					so.setStatus(Short.valueOf(SaleOrder.order_staus_over));
					so.setModifyTime(new Date()); //打印码单需求
					so.setModifier(creator); // 打印码单需求
					//saleOrderDao.merge(so);
					
					saleOrderDao.getHibernateTemplate().update(so); // 替换merge方法
					t = true;
				}else{
					log.error("Booking finance account listing data error with sales return : " + memo + " customer: " + cal.getCustomerName());
				}
			}
		}else{
			log.warn("data has null object ~!");
		}
		
		return t;
	}
	
	
	/**
	 * 剪样出入库填充
	 * @param so
	 * @param cio
	 * @param creator
	 */
	private void injectSampleCheckinoutItem(SaleOrder so, CheckInOut cio, String creator) {
		if(so != null && cio != null){
			List<SaleOrderItem> soItems = so.getItems();
			double totalMeterNum = 0;
			double totalPiNum = 0;
			for(SaleOrderItem soItem: soItems){
				if(soItem != null && soItem.getMeterNum() != null){
					CheckInOutItem cioItem = new CheckInOutItem();
					cioItem.setCheckInOut(cio);
					cioItem.setCreateTime(new Date());
					cioItem.setCreator(creator);
					cioItem.setModifier(creator);
					cioItem.setModifyTime(new Date());
					//新建出库的库存数据
					Storage tmpSampleCheckOutSt = new Storage();
					tmpSampleCheckOutSt.setProduct(soItem.getProduct());
					tmpSampleCheckOutSt.setMeterNum(Double.valueOf(soItem.getMeterNum()));
					tmpSampleCheckOutSt.setSampleFlag(true);
					tmpSampleCheckOutSt.setName(soItem.getProduct().getName());
					
					cioItem.setStorage(tmpSampleCheckOutSt);
					cioItem.setInputMeterNum(tmpSampleCheckOutSt.getMeterNum());
					
					if(cio.getItems() == null) cio.setItems( new ArrayList<CheckInOutItem>());
					cio.getItems().add(cioItem);
					totalPiNum++;
					totalMeterNum = totalMeterNum + Double.valueOf(soItem.getMeterNum());
				}
			}
			cio.setMeterNumSummary(totalMeterNum);
			cio.setPiNumSummary(totalPiNum);
			cio.setDescription("系统协助发货出库，销售订单号：" + so.getFlowNo());
		}
	}

	/**
	 * 普通大货销售、采购退货出入库填充
	 * @param cio
	 * @param flowNo
	 * @param creator
	 */
	private void injectCheckinoutItems(CheckInOut cio, String flowNo, String creator) {
		double totalMeterNum = 0;
		double totalPiNum = 0;
		Criteria cte = storageDao.createUnDeletedCriteria();
		cte.add(Restrictions.eq("chargedFlowNo", flowNo));
		cte.add(Restrictions.eq("chargeFlag", true));
		List<Storage> chargedStorageList = cte.list();
		List<CheckInOutItem> cioItemList = new ArrayList<CheckInOutItem>();
		for (Storage st : chargedStorageList) {
			if (st != null) {
				CheckInOutItem coItem = new CheckInOutItem();
				coItem.setStorage(st);
				coItem.setCheckInOut(cio);
				coItem.setCreator(creator);
				coItem.setCreateTime(new Date());
				coItem.setModifier(creator);
				coItem.setModifyTime(new Date());
				coItem.setInputMeterNum(st.getMeterNum());
				totalMeterNum = totalMeterNum + st.getMeterNum();
				totalPiNum++;
				cioItemList.add(coItem);
			}
		}
		cio.setItems(cioItemList);
		cio.setMeterNumSummary(totalMeterNum);
		cio.setPiNumSummary(totalPiNum);
		if(!StringUtils.isNotBlank(cio.getDescription())){
			//未填写描述信息时，系统自动追加描述信息
			cio.setDescription("系统协助发货出库，销售订单号：" + flowNo);
		}
	}

	/**
	 * 删除出入库数据，仅针对采购退货出库进行库存占用的清理
	 * @param id
	 * @return
	 */
	public boolean removeCIO(Long id){
		boolean t = false;
		if(id != null){
			CheckInOut cio = checkInOutDao.get(id);
			if(cio != null){
				if(cio.getDirection().shortValue() == CheckInOut.CHECKINOUT_DIRECTION_CHECKOUT
						&& cio.getType().shortValue() == CheckInOut.CHECKINOUT_TYPE_CHECKOUT_PURCHASE_RETURN){
					for(CheckInOutItem item :cio.getItems()){
						Storage st = item.getStorage();
						if(st != null && st.getId() != null){
							st = storageDao.get(st.getId());

							st.setChargeFlag(false);
							st.setChargedFlowNo(null);
							
//							storageDao.merge(st);
							storageDao.getHibernateTemplate().update(st); // 替换merge方法
							
						}
					}
				}
				
				checkInOutDao.remove(cio);
				t = true;
			}
		}
		return t;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springside.core.service.EntityService#getEntityDao()
	 */
	@Override
	public CheckInOutDao getEntityDao() {
		return checkInOutDao;
	}

	/**
	 * @return the checkInOutDao
	 */
	public CheckInOutDao getCheckInOutDao() {
		return checkInOutDao;
	}

	/**
	 * @param checkInOutDao
	 *            the checkInOutDao to set
	 */
	public void setCheckInOutDao(CheckInOutDao checkInOutDao) {
		this.checkInOutDao = checkInOutDao;
	}

	/**
	 * @return the storageDao
	 */
	public StorageDao getStorageDao() {
		return storageDao;
	}

	/**
	 * @param storageDao
	 *            the storageDao to set
	 */
	public void setStorageDao(StorageDao storageDao) {
		this.storageDao = storageDao;
	}

	/**
	 * @return the checkInOutItemDao
	 */
	public CheckInOutItemDao getCheckInOutItemDao() {
		return checkInOutItemDao;
	}

	/**
	 * @param checkInOutItemDao
	 *            the checkInOutItemDao to set
	 */
	public void setCheckInOutItemDao(CheckInOutItemDao checkInOutItemDao) {
		this.checkInOutItemDao = checkInOutItemDao;
	}

	/**
	 * @return the inventoryDao
	 */
	public InventoryDao getInventoryDao() {
		return inventoryDao;
	}

	/**
	 * @param inventoryDao
	 *            the inventoryDao to set
	 */
	public void setInventoryDao(InventoryDao inventoryDao) {
		this.inventoryDao = inventoryDao;
	}

	/**
	 * @return the saleOrderDao
	 */
	public SaleOrderDao getSaleOrderDao() {
		return saleOrderDao;
	}

	/**
	 * @param saleOrderDao
	 *            the saleOrderDao to set
	 */
	public void setSaleOrderDao(SaleOrderDao saleOrderDao) {
		this.saleOrderDao = saleOrderDao;
	}

	/**
	 * @return the purchaseOrderDao
	 */
	public PurchaseOrderDao getPurchaseOrderDao() {
		return purchaseOrderDao;
	}

	/**
	 * @param purchaseOrderDao
	 *            the purchaseOrderDao to set
	 */
	public void setPurchaseOrderDao(PurchaseOrderDao purchaseOrderDao) {
		this.purchaseOrderDao = purchaseOrderDao;
	}

	/**
	 * @return the shouldPaySummaryDao
	 */
	public ShouldPaySummaryDao getShouldPaySummaryDao() {
		return shouldPaySummaryDao;
	}

	/**
	 * @param shouldPaySummaryDao
	 *            the shouldPaySummaryDao to set
	 */
	public void setShouldPaySummaryDao(ShouldPaySummaryDao shouldPaySummaryDao) {
		this.shouldPaySummaryDao = shouldPaySummaryDao;
	}

	/**
	 * @return the shouldPayDao
	 */
	public ShouldPayDao getShouldPayDao() {
		return shouldPayDao;
	}

	/**
	 * @param shouldPayDao
	 *            the shouldPayDao to set
	 */
	public void setShouldPayDao(ShouldPayDao shouldPayDao) {
		this.shouldPayDao = shouldPayDao;
	}

	/**
	 * @return the staffDao
	 */
	public StaffDAO getStaffDao() {
		return staffDao;
	}

	/**
	 * @param staffDao
	 *            the staffDao to set
	 */
	public void setStaffDao(StaffDAO staffDao) {
		this.staffDao = staffDao;
	}

	public ProductDao getProductDao() {
		return productDao;
	}

	public void setProductDao(ProductDao productDao) {
		this.productDao = productDao;
	}

	/**
	 * @return the customerAccountListingDao
	 */
	public CustomerAccountListingDao getCustomerAccountListingDao() {
		return customerAccountListingDao;
	}

	/**
	 * @param customerAccountListingDao
	 *            the customerAccountListingDao to set
	 */
	public void setCustomerAccountListingDao(
			CustomerAccountListingDao customerAccountListingDao) {
		this.customerAccountListingDao = customerAccountListingDao;
	}

	/**
	 * @return the financeItemDao
	 */
	public FinanceItemDao getFinanceItemDao() {
		return financeItemDao;
	}

	/**
	 * @param financeItemDao
	 *            the financeItemDao to set
	 */
	public void setFinanceItemDao(FinanceItemDao financeItemDao) {
		this.financeItemDao = financeItemDao;
	}

	/*********************************** 没用的方法  ***************************/
	
	/**
	 * 取得页面参数，构成CHECKINOUT对象，并且保存
	 * 
	 * @param productname
	 * @param productcolor
	 * @param meterstring
	 * @param pi
	 * @param intype
	 * @param flowno
	 * @return
	 * @deprecated 
	 */
	@SuppressWarnings("unused")
	public short pageCheckInOutCio(String productname, String productcolor,
			String meterstring, String pi, String intype, String flowno) {
		CheckInOut cio = new CheckInOut();
		SaleOrder saleOrder = saleOrderDao.getSaleOrderByFlowNo(flowno);
		if (saleOrder == null) {
			return -1;
		}
		Product product = productDao.isExistSame(productname, productcolor);
		if (product == null) {
			return -2;
		}
		String array[] = meterstring.split(",");
		double totalmeter = 0;
		boolean inouttype = true;
		if (intype.equals("1") || intype.equals("2")) {
			inouttype = false;
		}

		for (int i = 0; i < array.length; i++) {
			totalmeter = totalmeter + Double.parseDouble(array[i]);
		}

		cio.setDirection(new Short("1"));
		cio.setMeterNumSummary(totalmeter);
		cio.setPiNumSummary(Double.parseDouble(pi));
		cio.setType(new Short(intype));
		cio.setSaleOrder(saleOrder);
		checkInOutDao.save(cio);

		for (int i = 0; i < array.length; i++) {
			if (inouttype) {
				List<Storage> stoList = storageDao.getSampleStorage(product.getName(), product.getColorCode());
				if (stoList != null && stoList.size() > 0) {
					Storage existSto = stoList.get(0);
					existSto.setMeterNum(existSto.getMeterNum()
							+ Double.parseDouble(array[i]));
//					storageDao.merge(existSto); // 同步新的库存到DB中
					storageDao.getHibernateTemplate().update(existSto); // 替换merge方法
				} else {
					// 库存中不存在对应的剪样，新增之
					storageDao.save(Double.parseDouble(array[i]));
				}
			} else {
				Storage storage = new Storage();
				storage.setProduct(product);
				storage.setName(productname);
				storage.setChargeFlag(false);
				storage.setSampleFlag(false);
				storage.setCreator("PDA");
				storage.setMeterNum(Double.parseDouble(array[i]));
				storageDao.save(storage);

				CheckInOutItem checkInOutItem = new CheckInOutItem();
				checkInOutItem.setStorage(storage);
				checkInOutItem.setCheckInOut(cio);
				checkInOutItem.setCreator("PDA");
				checkInOutItemDao.save(checkInOutItem);
			}
		}
		return 0;
	}
	
	/**
	 * 通过退单审核
	 * @param id
	 * @return
	 */
	public String updatePurchaseStatus(int id){
		String result ="";
		CheckInOut cio = this.checkInOutDao.get(new Integer(id).longValue());
		if(cio !=null){
			cio.setState("1");
			this.checkInOutDao.getHibernateTemplate().update(cio);
			result = "success";
		}
		return result;
	}

	/**
	 * @return the customerDao
	 */
	public CustomerDao getCustomerDao() {
		return customerDao;
	}

	/**
	 * @param customerDao the customerDao to set
	 */
	public void setCustomerDao(CustomerDao customerDao) {
		this.customerDao = customerDao;
	}

	/**
	 * @return the purchaseReturnDao
	 */
	public PurchaseReturnDao getPurchaseReturnDao() {
		return purchaseReturnDao;
	}

	/**
	 * @param purchaseReturnDao the purchaseReturnDao to set
	 */
	public void setPurchaseReturnDao(PurchaseReturnDao purchaseReturnDao) {
		this.purchaseReturnDao = purchaseReturnDao;
	}

	/**
	 * @return the purchaseReturnItemDao
	 */
	public PurchaseReturnItemDao getPurchaseReturnItemDao() {
		return purchaseReturnItemDao;
	}

	/**
	 * @param purchaseReturnItemDao the purchaseReturnItemDao to set
	 */
	public void setPurchaseReturnItemDao(PurchaseReturnItemDao purchaseReturnItemDao) {
		this.purchaseReturnItemDao = purchaseReturnItemDao;
	}	
}
